package com.yang.imbatis.factory;

import com.yang.dao.UserMapper;
import com.yang.dao.UserMapper1;


import java.lang.reflect.Proxy;

/**
 * @Description: 处理动态代理
 * @author: Yang Qiang
 * @create: 2021-10-18 21:28
 */
public class YangSession {

	public Object getMapper(Class clazz){
		/*
			jdk动态代理的原理:看教程Java动态代理
		 */
		/*
			参数1: 类加载器
				- 平时我们要new一个对象出来, 就需要有.class类文件在磁盘上,然后如果需要有.class类文件在磁上
				就也需要一个.java文件, 然后把.class文件加载到JVM上, 然后加载一个类到jvm上面就需要一个类加载器
				- 然后需要同一个类加载器来加载, 因为同一个类被不同的类加载器加载出来的对象是不同的,所以为了我们代理
				出来的对象被我们的当前(当前类)识别到, 所以就需要当前类的类加载器加载


			参数2:
				- 为什么是一个接口数组?
				因为在Java中是多实现的, 一个类可以实现多个接口

				- 参数作用1:对象里面的内容动态的产生(动态创建出来的代理类的代码), 那么这个代码怎么来
				就是从传的这个接口获取, 比如我们可以通过反射得到里面的方法(方法修饰符,返回类型,方法名字,方法参数个数)
				但是方法里面的方法体怎么动态的产生呢? 因为方法里面逻辑是动态的变化的, 我们不能通过接口再拿到了

				- 参数作用2:返回的对象必须要实现目标接口, 因为我们拿到后需要强转为指定的接口, 那么动态代理产生的对象也
				必须实现这个接口
				UserMapper userMapper = (UserMapper)yangSession.getMapper(UserMapper.class);

				- 通过参数2可以得到的Java代码
				目标方法:	@Select("select * from user")
							List<Map<String, Object>> findAll();
				可以动态得到的代码:还缺少了方法体:
							public class XX impl UserMapper{
								public List<Map<String, Object>> findAll(){

									return List<Map<String, Object>>;
								}
							}


			参数3:
				- 根据参数2我们知道, 暂时得不到方法的方法体(因为方法体是动态变化的), 那要怎么得到呢?
				比如得不到获取SQL语句, JDBC执行语句, 返回语句, 那这些代码怎么来呢?

				- 参数3解释: 这个参数是一个对象, 是一个实现函数式接口InvocationHandler的对象, 那么代码在执行的时候就
				肯定会走这个接口的唯一方法, 所以我们的这个参数的对象就会重写这个invoke方法, 然后上面的那些代码逻辑就我们
				就写到invoke方法里面, 然后我们动态代理生成的类里面的方法就执行invoke方法就行了, 也就是我们生成出来的代码
				是不可能动态的, 所以我们动态在invoke方法的内部.
				那么生成出来的类可能就是这样的:
					public class XX impl UserMapper{
								public List<Map<String, Object>> findAll(){
									h.invoke();
									return List<Map<String, Object>>;
								}
							}

				- 详细解释看这个参数类里面的注释

		 */
		ClassLoader classLoader = this.getClass().getClassLoader();
		Class[] classes = new Class[]{clazz};
		Object proxy = Proxy.newProxyInstance(classLoader, classes, new YangInvocationHandler());

		return proxy;
	}
}
